#ifndef __STVENANTKIRCHHOFF_H
#define __STVENANTKIRCHHOFF_H 1

#include <life/options.hpp>
#include <life/lifecore/application.hpp>

#include <life/lifealg/backend.hpp>
#include <life/lifediscr/functionspace.hpp>
#include <life/lifepoly/im.hpp>
#include <life/lifefilters/gmsh.hpp>
#include <life/lifefilters/exporter.hpp>
#include <life/lifemesh/meshmover.hpp>
#include <life/lifevf/vf.hpp>
#include <life/lifediscr/bdf2.hpp>


namespace Life
{

template<int Dim,
         int Order,
         template<uint16_type,uint16_type,uint16_type> class Entity>
class StVenantKirchhoff
{
public:

    typedef double value_type;

    typedef Application application_type;
    typedef boost::shared_ptr<application_type> application_ptrtype;

    typedef Backend<value_type> backend_type;
    typedef boost::shared_ptr<backend_type> backend_ptrtype;

    /*matrix*/
    typedef typename backend_type::sparse_matrix_ptrtype sparse_matrix_ptrtype;
    typedef typename backend_type::vector_ptrtype vector_ptrtype;

    /*mesh*/
    typedef Entity<Dim,1,Dim> convex_type;
    typedef Mesh<convex_type> mesh_type;
    typedef boost::shared_ptr<mesh_type> mesh_ptrtype;

    /*basis*/
    typedef Lagrange<Order, Vectorial> basis_u_type;
    typedef bases<basis_u_type> basis_type;

    /*space*/
    typedef FunctionSpace<mesh_type, basis_type,Continuous, double> space_struct_type;
    typedef boost::shared_ptr<space_struct_type> space_struct_ptrtype;

    BOOST_MPL_ASSERT( ( boost::is_same<typename space_struct_type::bases_list, basis_type> ) );

    /* functions */
    typedef typename space_struct_type::element_type element_struct_type;
    typedef boost::shared_ptr<element_struct_type> element_struct_ptrtype;


    typedef Bdf<space_struct_type>  bdf_struct_type;
    typedef boost::shared_ptr<bdf_struct_type> bdf_struct_ptrtype;

    /* export */
    typedef Exporter<mesh_type> exporter_type;
    typedef boost::shared_ptr<exporter_type> exporter_ptrtype;

    StVenantKirchhoff( application_ptrtype __appli )
        :
        M_lifeApplication(__appli),
        M_backend( backend_type::build( this->application()->vm() ) ),
        meshSize( this->application()->vm()["hsize"].template as<double>() ),
        M_mesh_struct(this->createMesh( meshSize )),
        M_Xh(new space_struct_type( M_mesh_struct ) ),
        U_displ_struct( new element_struct_type( M_Xh, "structure displacement" )),
        U_velocity_struct( new element_struct_type( M_Xh, "structure velocity" )),
        U_acceleration_struct( new element_struct_type( M_Xh, "structure acceleration" )),
        M_bdf_displ_struct ( new bdf_struct_type( this->application()->vm(),M_Xh,"structure displacement" )),
        M_bdf_velocity_struct ( new bdf_struct_type( this->application()->vm(),M_Xh,"structure velocity" )),
        M_bdf_acceleration_struct ( new bdf_struct_type( this->application()->vm(),M_Xh,"structure acceleration" )),
        M_exporter( exporter_type::New( this->application()->vm(), this->application()->about().appName() ) ),
        M_cpt_export(0)
    {

        penalbc = this->application()->vm()["bccoeff"].template as<value_type>();

        EE = 21*1e5;
        sigma = 0.28;
        mu = EE/(2*(1+sigma));
        lambda = EE*sigma/((1+sigma)*(1-2*sigma));


    }

    application_ptrtype application() { return M_lifeApplication; }

    mesh_ptrtype createMesh( double meshSize );

    //-----------------------------------------------------------------------------------//

    void init();

    void run();

    void updateJacobian( const vector_ptrtype& X, sparse_matrix_ptrtype& J );
    void updateResidual( const vector_ptrtype& X, vector_ptrtype& R );

    void updateBdf();

    //-----------------------------------------------------------------------------------//

private:

    void solve( sparse_matrix_ptrtype const& D, element_struct_type& u, vector_ptrtype const& F, bool is_sym );

    void exportResults( element_struct_type& u, element_struct_type& v );
    void exportResultsInstat( element_struct_type& u, element_struct_type& v,double time );

private:

    application_ptrtype M_lifeApplication;

    backend_ptrtype M_backend;

    double meshSize;
    mesh_ptrtype M_mesh_struct;

    MeshMover<mesh_type> M_mesh_mover;

    space_struct_ptrtype M_Xh;

    element_struct_ptrtype U_displ_struct;
    element_struct_ptrtype U_velocity_struct;
    element_struct_ptrtype U_acceleration_struct;

    bdf_struct_ptrtype M_bdf_displ_struct;
    bdf_struct_ptrtype M_bdf_velocity_struct;
    bdf_struct_ptrtype M_bdf_acceleration_struct ;

    //coef de penalisation
    double penalbc;

    //Paramètre du modèle
    double EE;
    double sigma;
    double mu;
    double lambda;

    //Exporteur
    exporter_ptrtype M_exporter;
    uint M_cpt_export;

}; // StVenantKirchhoff
} // Life
#endif /* __NSSTOKES_H */
